perm filename SCAN.MLI[MLI,LSP] blob
sn#166082 filedate 1975-06-28 generic text, type T, neo UTF8
BEGIN
% This program presents a set of functions which is equivalent to the
MLISP scanner. It is for the reference of users wanting to implement
MLISP on a LISP system without Quam's READ-modifying functions. In
order to use these functions, the function &SCAN in the MLISP
translator should be replaced by the &SCAN function below, and the
other functions added where convenient. The functions below are
written in MLISP, so their LISP translations would actually be used.
The scanner below places only two restrictions on the LISP system:
(1) There must be a READCH function, which reads the next character
in the input stream and returns that character as its value.
(2) There must be a READLIST function, which takes as its argument a
list of single characters and concatenates them to form an atom.
These two functions are taken to be primitives, and they are used
below without further explanation. &SCAN sets the global variables
&SCANTYPE and &SCANVAL as follows:
Syntactic Type Value of &SCANTYPE Value of &SCANVAL
<identifier> 0 the identifier
<string> 1 the string
<number> 2 the number
<delimiter> 3 the delimiter
!NEXT_CHAR is always set to the next character in the input stream
after the current token has been obtained.
%
SPECIAL ?&SCANVAL, ?&SCANTYPE, ?&IDTYPE, ?&NUMTYPE, ?&STRTYPE, ?&DELIMTYPE;
SPECIAL LPAR, RPAR, PERIOD, BLANK, CR, LF, FF, VT, TAB, ALTMODE, DBQUOTE, PERCENT;
SPECIAL !NEXT_CHAR, !MLISP_LITERALLY_CHAR, !LITERALLY_CHARACTER, !IVALUE, !ILENGTH;
SPECIAL ?&X?&, ?&Y?&, IBASE;
EXPR ?&SCAN ();
IF NUMBERP ?!NEXT_CHAR THEN SCAN_NUMBER() % Number %
ELSE IF LETTERP(?!NEXT_CHAR) THEN % Identifier %
SCAN_IDENTIFIER(NIL, ?!NEXT_CHAR)
ELSE IF ?!NEXT_CHAR EQ DBQUOTE THEN % String %
SCAN_STRING(<DBQUOTE>, READCH())
ELSE IF IGNOREP(?!NEXT_CHAR) THEN % Ignorable char %
DO NIL UNTIL NOT IGNOREP(?!NEXT_CHAR ← READCH())
ALSO ?&SCAN()
ELSE IF ?!NEXT_CHAR EQ PERCENT THEN % Comment %
BEGIN
DO NIL UNTIL READCH() EQ PERCENT;
?!NEXT_CHAR ← READCH();
RETURN ?&SCAN();
END
ELSE SCAN_DELIMITER(); % Delimiter %
EXPR SCAN_IDENTIFIER (L, NXT);
IF NUMBERP NXT OR GET(NXT, 'LETTER) THEN
SCAN_IDENTIFIER(NXT CONS L, READCH())
ELSE IF NXT EQ ?!MLISP_LITERALLY_CHAR THEN
SCAN_IDENTIFIER(READCH() CONS ?!LITERALLY_CHARACTER CONS L,
READCH())
ELSE BEGIN
?&SCANTYPE ← ?&IDTYPE;
?&SCANVAL ← READLIST REVERSE L;
IF ?&X?& AND GET(?&SCANVAL, '?&TRANS) THEN % DEFINE'ed symbol %
BEGIN
?&SCANTYPE ← GET(?&SCANVAL, '?&TRANSTYPE);
?&SCANVAL ← GET(?&SCANVAL, '?&TRANS);
END;
?!NEXT_CHAR ← NXT; % Set !NEXT_CHAR %
END;
EXPR SCAN_STRING (L, NXT);
IF NXT EQ DBQUOTE THEN
BEGIN
?&SCANTYPE ← ?&STRTYPE;
?&SCANVAL ← READLIST REVERSE(NXT CONS L);
?!NEXT_CHAR ← READCH(); % Set !NEXT_CHAR %
END
ELSE SCAN_STRING(NXT CONS L, READCH());
EXPR SCAN_DELIMITER ();
BEGIN
?&SCANTYPE ← ?&DELIMTYPE;
?&SCANVAL ← ?!NEXT_CHAR; % delim → &SCANVAL %
IF ?&X?& AND GET(?&SCANVAL, '?&TRANS) THEN
BEGIN % DEFINE'ed symbol %
?&SCANTYPE ← GET(?&SCANVAL, '?&TRANSTYPE);
?&SCANVAL ← GET(?&SCANVAL, '?&TRANS);
END;
?!NEXT_CHAR ← READCH(); % Set !NEXT_CHAR %
END;
EXPR LETTERP (CHAR);
GET(CHAR, 'LETTER) OR CHAR EQ ?!MLISP_LITERALLY_CHAR;
EXPR IGNOREP (CHAR);
GET(CHAR, 'IGNORE);
EXPR SREAD (); % Read sexpression %
PROG2(?&SCAN(), SREAD1());
EXPR SREAD1 ();
IF ?&SCANVAL EQ LPAR AND ?&SCANTYPE EQ 3 THEN % ( %
?&SCAN() ALSO SREAD2()
ELSE ?&SCANVAL;
EXPR SREAD2 ();
IF ?&SCANVAL EQ RPAR AND ?&SCANTYPE EQ 3 THEN % ) %
NIL
ELSE BEGIN NEW X;
X ← SREAD1();
?&SCAN();
RETURN X CONS SREAD3();
END;
EXPR SREAD3 ();
IF ?&SCANVAL EQ PERIOD AND ?&SCANTYPE EQ 3 THEN % . %
BEGIN NEW X; % Dotted pair (A.B) %
X ← SREAD1(); % Get the "B" part %
?&SCAN(); % Get rid of the ) %
RETURN X;
END
ELSE SREAD2();
EXPR SCAN_NUMBER ();
BEGIN NEW ?!IVALUE, ?!ILENGTH, N, X;
SCAN_INTEGER(?!NEXT_CHAR, 0, 0); % Scan an integer %
N ← ?!IVALUE; % Save it %
IF ?!NEXT_CHAR EQ '?. THEN % Decimal number %
BEGIN
SCAN_INTEGER(READCH(), 0, 0); % Scan decimal part %
N ← N + ?!IVALUE / EXP(10.0, ?!ILENGTH);
END;
IF ?!NEXT_CHAR EQ 'E THEN % Exponent %
BEGIN
?!NEXT_CHAR ← READCH(); % + or - ? %
IF ?!NEXT_CHAR EQ '?+ THEN X ← 10.0 % + %
ALSO ?!NEXT_CHAR ← READCH()
ELSE IF ?!NEXT_CHAR EQ '?- THEN X ← 0.1 % - %
ALSO ?!NEXT_CHAR ← READCH()
ELSE X ← 10.0;
SCAN_INTEGER(?!NEXT_CHAR, 0, 0); % Get the exponent %
N ← N * EXP(X, ?!IVALUE);
END;
% Now we've got the whole number %
?&SCANTYPE ← ?&NUMTYPE;
?&SCANVAL ← N; % Value %
END;
EXPR SCAN_INTEGER (NXT, N, LEN); % Scan an integer %
IF NUMBERP NXT THEN
SCAN_INTEGER(READCH(), N*IBASE + NXT, LEN+1)
ELSE BEGIN
?!IVALUE ← N; % Value %
?!ILENGTH ← LEN; % # digits %
?!NEXT_CHAR ← NXT; % Set !NEXT_CHAR %
END;
EXPR EXP (N, E); % Exponent function %
IF E = 0 THEN 1.0 % Exponent is 0 %
ELSE IF E = 2*(E/2) THEN EXP(N*N, E/2) % Exponent is even %
ELSE N * EXP(N*N, (E-1)/2); % Exponent is odd %
% Calling the following function will initialize the property lists
needed by the functions above %
EXPR SCANINIT ();
BEGIN
FOR NEW CHAR IN
'(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
_ ?: ?!) DO
PUTPROP(CHAR, T, 'LETTER);
FOR NEW CHAR IN <BLANK,CR,LF,FF,VT,TAB,ALTMODE> DO
PUTPROP(CHAR, T, 'IGNORE);
?!LITERALLY_CHARACTER ← '?/; % LISP literally char (/) %
?!MLISP_LITERALLY_CHAR ← '??; % MLISP literally char (?) %
?!NEXT_CHAR ← BLANK; % Scanner starts blank %
END;
EXPR SCANSET (); NIL; % Dummy definitions %
EXPR SCANRESET (); NIL;
% The LISP translation of this program is listed in the following
section. It has been printed using a program called PPRINT, an
s-expression formatting (pretty-printing) program. This program is
written in MLISP and is included with the MLISP system. (All of the
files in the MLISP system are listed in SECTION 4.3 .) Note that
FOR-loops, WHILE-loops and UNTIL-loops have been expanded by macros
into in-line code %
END.